home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / a86b.arc / MACRO.DOC < prev    next >
Text File  |  1986-06-23  |  17KB  |  432 lines

  1. ---MACRO.DOC---
  2.  
  3. Macro Facility
  4. ----- --------
  5.  
  6. This assembler contains an easy-to-use, but very powerful macro facility.
  7. The facility subsumes the capabilities of most assemblers, including operand
  8. concatenation, indefinite repeat (often called IRP), and indefinite-repeat
  9. character (IRPC).  Unlike other assemblers, this assembler integrates these
  10. functions into the main macro facility; so they can be invoked without clumsy
  11. syntax, or strange characters in the macro-call operands.
  12.  
  13.  
  14.  
  15. Simple Macro Syntax
  16.  
  17. All macros must be defined before they are used.  A macro definition consists
  18. of the name of the macro, followed by the word MACRO, followed by the text of
  19. the macro, followed by #EM, which marks the end of the macro.
  20.  
  21. Many assembly languages require a list of dummy operand-names to follow the
  22. word MACRO.  This assembler does not: the operands are denoted in the text
  23. with the fixed names #1, #2, #3, ... up to a limit of #9, for each operand
  24. in order.  If there is anything following the word MACRO, it is considered
  25. part of the macro text.
  26.  
  27. Examples:
  28.  
  29. ; CLEAR sets the register-operand to zero.
  30.  
  31. CLEAR  MACRO  SUB #1,#1 #EM
  32.  
  33.   CLEAR AX        ; generates a SUB AX,AX instruction
  34.   CLEAR BX        ; generates a SUB BX,BX instruction
  35.  
  36. ; MOVM moves the second operand to the first operand.  Both operands can be
  37. ;   memory-variables.
  38.  
  39. MOVM  MACRO
  40.   MOV AX,#2
  41.   MOV #1,AX
  42. #EM
  43.  
  44. VAR1  DB  ?
  45. VAR2  DB  ?
  46.  
  47. MOVM VAR1,VAR2    ; generates MOV AX,VAR2 followed by MOV VAR1,AX
  48.  
  49.  
  50.  
  51. Formatting in macro definitions and calls
  52.  
  53. The format of a macro definition is flexible.  If the macro text consists of a
  54. single instruction, the definition can be given in a single line, as in the
  55. CLEAR macro given above.  There is no particular advantage to doing this,
  56. however: the assembler prunes all unnecessary spaces, blank lines, and
  57. comments from the macro text before entering the text into the symbol table.
  58. I recommend the more spread-out format of the MOVM macro, for program
  59. readability.
  60.  
  61. All special macro-operators within a macro definition begin with a pound-sign
  62. #.  The letters following the pound-sign can be given in either upper-case or
  63. lower-case.  Pound-sign operators are recognized even within quoted strings.  If
  64. you wish the pound-sign to be treated literally, and not as the start of a
  65. special macro-operator, you must give 2 consecutive pound signs: ##.  For
  66. example:
  67.  
  68. FOO MACRO
  69.   DB '##1'
  70.   DB '#1'
  71. #em
  72.  
  73. FOO abc      ; produces  DB '#1'  followed by  DB 'abc'
  74.  
  75. The format of the macro call line is also flexible.  A macro call consists of
  76. the name of the macro, followed by the operands to be plugged into the macro.
  77. The assembler prunes leading and trailing blanks from the operands of a
  78. macro call.  The operands to a macro call are always separated by commas.
  79. Also, as in all assembler source lines, a semi-colon occurring outside of
  80. a quoted-string is the start of a comment, ignored by the assembler.  If you
  81. want to include commas, blanks, or semi-colons in your operands, you must
  82. enclose your operand in single-quotes.
  83.  
  84.  
  85.  
  86. Macro operand substitution
  87.  
  88. Some macro assemblers expect the operands to macro calls to follow the same
  89. syntax as the operands to instructions.  In those assemblers, the operands
  90. are parsed, and reduced to numeric values before being plugged into the
  91. macro definition text.  This is called "passing by value".  This assembler
  92. does not pass by value, it passes by text.  The only parsing of operands
  93. done by the macro processor is to determine the start and the finish of the
  94. operand text.  That text is substituted, without regard for its contents,
  95. for the "#n" that appears in the macro definition.  The text is interpreted
  96. by the assembler only after a complete line is expanded and as it is assembled.
  97.  
  98. If the first non-blank character after the macro name is a comma, then the
  99. first operand is null: any occurrances of #1 in the macro text will be
  100. deleted, and replaced with nothing.  Likewise, any two consecutive commas
  101. with no non-blanks between them will result in the corresponding null
  102. operand.  Also, out-of-range operands are null; for example, #3 is a null
  103. operand if only two operands are provided in the call.
  104.  
  105. Null operands to macros are not in themselves illegal.  They will produce
  106. errors only if the resulting macro expansion is illegal.
  107.  
  108. The method of passing by text allows operand-text to be plugged anywhere
  109. into a macro, even within symbol names.  For example:
  110.  
  111. ; KF_ENTRY creates an entry in the KFUNCS table, consistsing of a pointer
  112. ;   to a KF_-action-routine.  It also declares the corresponding CF_-symbol,
  113. ;   which is the index within the table for that entry.
  114.  
  115. KF_ENTRY  MACRO
  116.   CF_#1  EQU  ($-KFUNCS)/2+080
  117.   DW  KF_#1
  118. #EM
  119.  
  120. KFUNCS:
  121.   KF_ENTRY  UP
  122.   KF_ENTRY  DOWN
  123.  
  124. ; The above code is equivalent to:
  125. ;
  126. ;  KFUNCS:
  127. ;    DW KF_UP
  128. ;    DW KF_DOWN
  129. ;
  130. ;  CF_UP    EQU  080
  131. ;  CF_DOWN  EQU  081
  132.  
  133.  
  134.  
  135. Quoted-string operands
  136.  
  137. As mentioned before, if you want to include blanks, commas, or semicolons in
  138. your operands, you enclose the operand in single-quotes.  In the vast majority
  139. of cases in which these special characters need to be part of operands, the
  140. user wants them to be quoted in the final, assembled line also.  Therefore, the
  141. quotes are passed in the operand.  To override this, and strip the quotes from
  142. the string, you precede the quoted string with a pound-sign.  Examples:
  143.  
  144. DBW  MACRO
  145.   DB  #1
  146.   DW  #2
  147. #EM
  148.  
  149. DBW  'E', E_POINTER
  150. DBW  'W', W_POINTER
  151.  
  152. ; note that if quotes were not passed, the above lines would have to be
  153. ;   DBW  '''E''', E_POINTER;    DBW  '''W''', W_POINTER
  154.  
  155. GENERAL_PUSH  MACRO
  156.   PUSH#1
  157. #EM
  158.  
  159. GENERAL_PUSH  F        ; generates a PUSHF instruction
  160. GENERAL_PUSH  #' AX'   ; generates a PUSH AX instruction
  161.  
  162. The fact that I could not come up with a more useful example than GENERAL_PUSH
  163. is strong evidence that it is much better to pass the quotes as the default
  164. action.
  165.  
  166.  
  167. Looping by operands in macros
  168.  
  169. This macro facility contains two kinds of loops: you can loop once for each
  170. operand in a range of operands; or you can loop once for each character within
  171. an operand.  The first kind of loop, the R-loop, is discussed in this section;
  172. the second kind, the C-loop, is discussed later.
  173.  
  174. An R-loop is a stretch of macro-definition code that is repeated when the macro
  175. is expanded.  In addition to the fixed operands #1 through #9, you can specify
  176. a variable operand, whose number changes each time through the loop.  You give
  177. the variable operand one of the 4 names #W, #X, #Y, or #Z.
  178.  
  179. An R-loop begins with #R, followed immediately by the letter W,X,Y, or Z naming
  180. the variable, followed by the number of the first operand to be used, followed
  181. by the number of the last operand to be used.  After the #Rxnn is the text to
  182. be repeated.  The R-loop ends with #ER.  For example:
  183.  
  184. STORE3 MACRO
  185.   MOV AX,#1
  186. #RY24               ; "repeat for Y running from 2 through 4"
  187.   MOV #Y,AX
  188. #ER
  189. #EM
  190.  
  191. STORE3  VAR1,VAR2,VAR3,VAR4
  192.  
  193. ; the above call produces the 4 instructions MOV AX,VAR1; MOV VAR2,AX;
  194. ;   MOV VAR3,AX; MOV VAR4,AX.
  195.  
  196.  
  197.  
  198. The #L last operator and indefinite repeats
  199.  
  200. The macro facility recognizes the special operator #L, which is the last
  201. operand in a macro call.  #L can appear anywhere in macro text; but its big
  202. power occurs in conjunction with R-loops, to yield an indefinite-repeat
  203. facility.
  204.  
  205. A common example is as follows: you can take any macro that is designed
  206. for one operand, and easily convert it into a macro that accepts any number
  207. of operands.  You do this by placing the command #RX1L, "repeat for X running
  208. from 1 through L", at the start of the macro, and the command #ER at the end
  209. just before the #EM.  Finally, you replace all instances of #1 in the macro
  210. with #X.  We see how this works with the CLEAR macro:
  211.  
  212. CLEAR MACRO #RX1L
  213.   SUB #X,#X
  214. #ER
  215. #EM
  216.  
  217. CLEAR  AX,BX      ; genearates both SUB AX,AX and SUB BX,BX in one macro-call!
  218.  
  219. It is possible for R-loops to iterate zero times.  In this case, the loop-text
  220. is skipped completely.  For example, CLEAR without any operands would produce no
  221. expanded text.
  222.  
  223. Character-loops
  224.  
  225. We have seen the R-loop; now we discuss the other kind of loop in macros,
  226. the character-loop, or C-loop.  In the C-loop, the variable W,X,Y, or Z
  227. does not represent an entire operand; it represents a character within an
  228. operand.
  229.  
  230. You start a C-loop with #C, followed by one of the 4 letters W,X,Y, or Z,
  231. followed by a single operand-specifier.  Following the #Cxn is the text of
  232. the C-loop.  The C-loop ends with #EC.  The macro will loop once for every
  233. character in the operand.  That single character will be substituted for each
  234. instance of the indicated variable-operand.  For example:
  235.  
  236. PUSHC  MACRO  #CW1
  237.   PUSH #WX
  238. #EC#EM
  239.  
  240. PUSHC ABC     ; generates the 3 instructions PUSH AX; PUSH BX; PUSH CX
  241.  
  242. If the C-operand is quoted in the macro call, the quotes ARE removed from
  243. the operand before passing characters to the loop.  It is not necessary
  244. to precede the quoted string with a pound-sign in this case.  If you do,
  245. the pound-sign will be passed as the first character.
  246.  
  247. If the C-operand is a null operand (no characters in it), the loop-text
  248. is skipped completely.
  249.  
  250.  
  251.  
  252. The "B"-before and "A"-after operators
  253.  
  254. So far, we have seen that you can specify operands in your macro in fourteen
  255. different ways: 1,2,3,4,5,6,7,8,9,W,X,Y,Z,L.  We now multiply these 14
  256. possibilities, by introducing the "A" and "B" operators.  You can precede any
  257. of the 14 specifiers with "A" or "B", to get the adjacent operand after
  258. or before the specified operand.  For example, BL means the operand just
  259. before the last operand; in other words, the second-to-the-last operand.
  260. AZ means the operand just after the Z operand.  You can even repeat, up to
  261. a limit of 4 "B"s or 3 "A"s:  BBL is the third-to-last operand; #AAA9 can be
  262. used where you would want to (but cannot) use #12.
  263.  
  264. In the case of the variable operand to a C-loop, the "A" and "B" specifiers
  265. denote the characters before or after the current looping-character.  An
  266. example of this is given in the next section.
  267.  
  268.  
  269.  
  270. Multiple-increments within loops
  271.  
  272. We have seen that you end an R-loop with a #ER, and you end a C-loop with
  273. a #EC.  We now present another way to end these loops; a way that lets you
  274. specify a larger increment to the macro's loop-counter.  You can end your
  275. loops with one of the 4 additional commands #E1, #E2, #E3, or #E4.
  276.  
  277. For R-loops terminated by #ER, the variable-operand advances to the next
  278. operand when the loop is made.  If you end your R-loop with #E2, the variable-
  279. operand advances 2 operands, not just one.  For #E3, it advances 3 operands;
  280. for #E4, 4 operands.  The #E1 command is the same as #ER.
  281.  
  282. The most common usage of this feature is as follows:  You will recall that we
  283. generalized the CLEAR macro with an R-loop, so that it would take an
  284. indefinite number of operands.  Suppose we want to do the same thing with
  285. the DBW macro.  We would like DBW to take any number of operands, and
  286. alternate DBs and DWs indefinitely on the operands.  This is made possible
  287. by creating an R-loop terminated by #E2:
  288.  
  289. DBW  MACRO  #RX1L
  290.   DB  #X
  291.   DW  #AX
  292. #E2
  293. #EM
  294.  
  295. DBW  'E',E_POINTER,  'W',W_POINTER    ; two pairs on the same line!
  296.  
  297. The #E2 terminator means that we are looping on a pair of operands.
  298. Note the crucial usage of the "A"-after operator to specify the second
  299. operand of the operand-pair.
  300.  
  301. A special note applies to the DBW macro above: the assembler just happens to
  302. accept a DW directive with no operands (it generates no object code, and
  303. issues no error).  This means that DBW will accept an odd number of operands
  304. with no error, and do the expected thing (it alternates bytes and words, ending
  305. with a byte).
  306.  
  307. You could likewise genralize a macro with 3 or 4 operands, to an indefinite
  308. number of triples or quadruples; by ending the R-loop with #E3 or #E4.  The
  309. operands in each group would be specified by #X, #AX, #AAX, and, for #E4,
  310. #AAAX.
  311.  
  312. For C-loops terminated by #E1 through #E4, the character-pointer is advanced
  313. the specified number of characters.  You use this in much the same way as for
  314. R-loops, to create loops on pairs, triplets, and quadruplets of characters.
  315. For example:
  316.  
  317. PUSHC2  MACRO  #CZ1
  318.   PUSH #Z#AZ
  319. #E2
  320. #EM
  321.  
  322. PUSHC2  AXBXSIDI    ; generates PUSH AX; PUSH BX; PUSH SI; PUSH DI
  323.  
  324. Negative R-loops
  325.  
  326. We now introduce another form of R-loop, called the Q-loop-- the negative
  327. repeat-loop.  This loop is the same as the R-loop, except that the operand
  328. number decrements instead of increments; and the loop exits when the number
  329. falls below the finish-number, not above it.  The Q-loop is specified by
  330. #Qxnn instead of #Rxnn, and #EQ instead of #ER.  You can also use the
  331. multiple-decrement forms #E1 #E2 #E3 or #E4 to terminate an Q-loop.
  332.  
  333. Example:
  334.  
  335. MOVN MACRO #QXL2   ; "negative-repeat X from L down to 2"
  336.   MOV #BX,#X
  337. #EQ#EM
  338.  
  339. MOVN AX,BX,CX,DX    ; generates the three instructions:
  340.                     ;    MOV CX,DX
  341.                     ;    MOV BX,CX
  342.                     ;    MOV AX,BX
  343.  
  344. Note: the above functionality is already built into the MOV instruction of
  345. the assembler.  The macro shows how you would implement it if you did not
  346. already have this facility.
  347.  
  348.  
  349.  
  350. Nesting of loops in macros
  351.  
  352. This macro facility allows nesting of loops within each other.  Since we
  353. provide the 4 identifiers W,X,Y,Z for the loop-operands, you can nest to
  354. a level of 4 without restriction-- just use a different letter for each
  355. nesting level.  You can nest even deeper, subject to the restriction that
  356. a letter W,X,Y,Z refers to the innermost containing loop that defines it.
  357.  
  358.  
  359.  
  360. Implied closing of loops
  361.  
  362. If you have a loop or loops ending when the macro ends, and if the iteration
  363. count for those loops is 1, you may omit the #ER, #EC, or #EQ.  The assembler
  364. closes all open loops when it sees #EM, with no error.
  365.  
  366. For example, if you omit the #ER for the loop-version of the CLEAR macro,
  367. it would make no difference-- the assembler automatically places an #ER
  368. code into the macro definition for you.
  369.  
  370. Local labels in macros
  371.  
  372. Some assemblers have a LOCAL pseudo-op that is used in conjunction with
  373. macros.  Symbols declared LOCAL to a macro have unique (and bizarre)
  374. symbol-names substituted for them each time the macro is called.  This
  375. solves the problem of duplicate label definitions when a macro is called
  376. more than once.
  377.  
  378. In this assembler, the problem is solved more elegantly, by having a class
  379. of generic local labels throughout assembly, not just in macros.  Recall
  380. that symbols consisting of a single letter, followed by one or more
  381. decimal digits, can be redefined.  You can use such labels in your macro
  382. definitions.
  383.  
  384. I have recommended that local labels outside of macros be designated L1
  385. through L9.  Within macro definitions, I suggest that you use labels
  386. M1 through M9.  If you used an Ln-label within a macro, you would have
  387. to make sure that you never call the macro within the range of definition
  388. of another Ln-label with the same name.  By using Mn-labels, you avoid
  389. such potential conflicts.
  390.  
  391. The following example of a local label within a macro is taken from the
  392. source of the macro-processor itself:
  393.  
  394. ; "JPOUND label" checks to see if AL is a pound sign.  If it is, it processes
  395. ;    the pound-sign term, and jumps to label.  Otherwise, it drops through
  396. ;    to the following code.
  397.  
  398. JPOUND MACRO
  399.   CMP AL,'##'         ; is the scanned character a pound-sign?
  400.   JNE >M1             ; skip if not
  401.   CALL MDEF_POUND     ; process the pound sign
  402.   JMP #1              ; jump to the label provided
  403. M1:
  404.   #EM
  405.  
  406.   ...
  407. L3:                   ; loop here to consume empty lines and leading blanks
  408.   CALL SKIP_BLANKS    ; skip over the leading blanks of a line
  409.   INC SI              ; advance source pointer beyond the next non-blank
  410.   JPOUND L3           ; if pound-sign then process, and consume more blanks
  411.   CMP AL,0A           ; were the blanks terminated by a linefeed?
  412.   JE L3               ; loop if yes, nothing on this line
  413. L5:                   ; loop here after a line is seen to have contents
  414.   CMP AL,';'          ; have we reached the start of a comment?
  415.   JE L1               ; jump if yes, to consume the comment
  416.   JPOUND >L6          ; if pound-sign then process it, and get another char
  417.   ...
  418. L6:
  419.   LODSB               ; fetch the next definition-char from the source
  420.   CMP AL,' '          ; is it blank?
  421.   JA L5               ; loop if not, to process it
  422.   ...
  423.  
  424.  
  425.  
  426. Debugging macro expansions
  427.  
  428. There is a tool called EXMAC which will help you troubleshoot program lines
  429. that call macros.  If you are not sure about what code is being generated by
  430. your macro calls, EXMAC will tell you.  See the file EXMAC.DOC for details.
  431.  
  432.